package service

import (
	"cat_mouse/core/dao"
	m "cat_mouse/core/model"
	"cat_mouse/infra/common"
	"cat_mouse/infra/model"
	"cat_mouse/infra/service/message"
	"cat_mouse/infra/utils"
	"cat_mouse/infra/utils/log"
	"cat_mouse/infra/utils/redis"
	"fmt"
	"github.com/pkg/errors"
	"strconv"
	"time"
)

type IValidCodeService interface {
	SendValidCode(phone string) (string, error)
	CleanExpireCode()
}

type ValidCodeService struct {
	validCodeDao *dao.ValidCodeDao
}

func (v *ValidCodeService) SendValidCode(phone string) (string, error) {
	var (
		rows        []*m.ValidCode
		expireAtInt = 60
		sysCfg      *model.SysCfg
		redisPrefix = common.RedisValidCodePrefix
		code        string
		err         error
	)
	if utils.GetSysCfg().ValidCodeExpire != 0 {
		expireAtInt = sysCfg.ValidCodeExpire
	}
	// 首先从Redis获取对应的code值，防止恶意刷code
	if code, err = redis.Get(fmt.Sprintf(redisPrefix, phone)); err == nil {
		return code, nil
	}
	// 校验当前手机号码的验证码是否存在
	if rows, err = v.validCodeDao.GetByExpireAt(phone, time.Now()); err != nil {
		return "", errors.Wrap(err, common.SearchMySQLError)
	}
	if len(rows) > 0 {
		return rows[0].Code, nil
	}
	codeInt := utils.RandomInt(10000, 99999)
	code = strconv.Itoa(codeInt)
	if err = v.validCodeDao.Create(&m.ValidCode{
		Phone:    phone,
		Code:     code,
		ExpireAt: common.JSONTime{Time: time.Now().Add(time.Duration(expireAtInt) * time.Second)},
	}); err != nil {
		return "", errors.Wrap(err, common.InsertMySQLError)
	}
	_ = redis.Set(fmt.Sprintf(redisPrefix, phone), code, expireAtInt)
	go message.ShortMsgFactory("aliyun").SendMessage(phone, code)
	return code, nil
}

func (v *ValidCodeService) CleanExpireCode() {
	if err := v.validCodeDao.DelByExpireAt(time.Now()); err != nil {
		log.Logger.Error(err)
	}
}

func NewValidCodeService() IValidCodeService {
	return &ValidCodeService{
		dao.NewValidCodeDao(),
	}
}
